﻿Imports System
Imports System.Runtime.InteropServices
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.Activities
    <ComVisible(False)> _
    Friend NotInheritable Class SetStateValidator
        Inherits ActivityValidator
        ' Methods
        Friend Shared Function IsValidContainer(ByVal activity As CompositeActivity) As Boolean
            Return (TypeOf activity Is EventDrivenActivity OrElse TypeOf activity Is StateInitializationActivity)
        End Function

        Public Overrides Function Validate(ByVal manager As ValidationManager, ByVal obj As Object) As ValidationErrorCollection
            Dim validationErrors As New ValidationErrorCollection(MyBase.Validate(manager, obj))
            Dim setState As SetStateActivity = [TryCast](obj,SetStateActivity)
            If (setState Is Nothing) Then
                Throw New ArgumentException(SR.GetString("Error_UnexpectedArgumentType", New Object() { GetType(StateActivity).FullName }), "obj")
            End If
            If SetStateContainment.Validate(setState, validationErrors) Then
                If String.IsNullOrEmpty(setState.TargetStateName) Then
                    validationErrors.Add(New ValidationError(SR.GetString("Error_PropertyNotSet", New Object() { "TargetStateName" }), &H116, False, "TargetStateName"))
                    Return validationErrors
                End If
                Dim state As StateActivity = StateMachineHelpers.FindStateByName(StateMachineHelpers.GetRootState(StateMachineHelpers.FindEnclosingState(setState)), setState.TargetStateName)
                If (state Is Nothing) Then
                    validationErrors.Add(New ValidationError(SR.GetError_SetStateMustPointToAState, &H5F3, False, "TargetStateName"))
                    Return validationErrors
                End If
                If Not StateMachineHelpers.IsLeafState(state) Then
                    validationErrors.Add(New ValidationError(SR.GetError_SetStateMustPointToALeafNodeState, &H5F4, False, "TargetStateName"))
                End If
            End If
            Return validationErrors
        End Function


        ' Nested Types
        Private Class SetStateContainment
            ' Methods
            Private Sub New()
            End Sub

            Public Shared Function Validate(ByVal setState As SetStateActivity, ByVal validationErrors As ValidationErrorCollection) As Boolean
                Dim containment As New SetStateContainment
                SetStateContainment.ValidateContainment(containment, setState)
                If (containment.validParentFound AndAlso containment.validParentStateFound) Then
                    Return True
                End If
                validationErrors.Add(New ValidationError(SR.GetError_SetStateOnlyWorksOnStateMachineWorkflow, &H5F2))
                Return False
            End Function

            Private Shared Sub ValidateContainment(ByVal containment As SetStateContainment, ByVal activity As Activity)
                If ((activity.Parent Is Nothing) OrElse (activity.Parent Is activity)) Then
                    containment.validParentFound = False
                ElseIf SetStateValidator.IsValidContainer(activity.Parent) Then
                    SetStateContainment.ValidateParentState(containment, activity.Parent)
                Else
                    SetStateContainment.ValidateContainment(containment, activity.Parent)
                End If
            End Sub

            Private Shared Sub ValidateParentState(ByVal containment As SetStateContainment, ByVal activity As CompositeActivity)
                If (Not activity.Parent Is Nothing) Then
                    If TypeOf activity.Parent Is StateActivity Then
                        containment.validParentStateFound = True
                    Else
                        SetStateContainment.ValidateParentState(containment, activity.Parent)
                    End If
                End If
            End Sub


            ' Fields
            Private validParentFound As Boolean = True
            Private validParentStateFound As Boolean
        End Class
    End Class
End Namespace

